import 'dart:convert';
import 'dart:io';

import 'package:casdon/common/utils/string_externtion.dart';
import 'package:casdon/core/logger/log.dart';
import 'package:casdon/core/utils/device_utils.dart';
import 'package:casdon/core/utils/shared_preferences_utils.dart';
import 'package:casdon/modules/home/data/api/splash_list_api.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:crypto/crypto.dart';

class CachedSplashEntry {
  final ResponseSplashListApi data;
  final String? localImagePath;

  CachedSplashEntry({required this.data, required this.localImagePath});

  Map<String, dynamic> toJson() => {
    'data': data.toJson(),
    'localImagePath': localImagePath,
  };

  factory CachedSplashEntry.fromJson(Map<String, dynamic> json) {
    return CachedSplashEntry(
      data: ResponseSplashListApi.fromJson(
        Map<String, dynamic>.from(json['data'] as Map),
      ),
      localImagePath: json['localImagePath'] as String?,
    );
  }
}

class SplashCacheService {
  SplashCacheService({Dio? dio})
    : _dio =
          dio ??
          Dio(
            BaseOptions(
              connectTimeout: const Duration(seconds: 10),
              receiveTimeout: const Duration(seconds: 10),
            ),
          );

  static const _storageKey = 'cached_splash_entries2';
  static const _cacheDirName = 'splash_cache';

  final Dio _dio;

  Future<void> cacheSplashList(List<ResponseSplashListApi>? list) async {
    if (list == null || list.isEmpty) {
      // 删除已有缓存，防止展示失效的本地图片
      await clearCache();
      return;
    }

    try {
      final directory = await _ensureCacheDirectory();
      final entries = <CachedSplashEntry>[];

      for (final item in list!) {
        final localPath = await _downloadImage(item.imageSrc, directory);
        entries.add(CachedSplashEntry(data: item, localImagePath: localPath));
      }

      await _persistEntries(entries);
      await _cleanupObsoleteFiles(
        directory,
        entries.map((e) => e.localImagePath).whereType<String>().toSet(),
      );
    } catch (e, s) {
      Log.e("缓存 Splash 数据失败", e, s);
    }
  }

  Future<List<CachedSplashEntry>> loadCachedSplashes() async {
    Log.d("解析缓存 Splash 数据");
    final sp = await SPUtils.getInstance();
    final raw = sp.getString(_storageKey);
    if (raw.isEmpty) return [];
    try {
      final List<dynamic> list = jsonDecode(raw) as List<dynamic>;

      final ret = list
          .map(
            (e) =>
                CachedSplashEntry.fromJson(Map<String, dynamic>.from(e as Map)),
          )
          .toList();
      Log.d("解析缓存 Splash 数据 成功${ret.toString()}");
      return ret;
    } catch (e, s) {
      Log.e("解析缓存 Splash 数据失败", e, s);
      return [];
    }
  }

  Future<void> clearCache() async {
    final sp = await SPUtils.getInstance();
    await sp.remove(_storageKey);
    final directory = await _ensureCacheDirectory();
    if (await directory.exists()) {
      await directory.delete(recursive: true);
    }
  }

  Future<void> _persistEntries(List<CachedSplashEntry> entries) async {
    final sp = await SPUtils.getInstance();
    final jsonStr = jsonEncode(
      entries.map((e) => e.toJson()).toList(growable: false),
    );
    await sp.setString(_storageKey, jsonStr);
  }

  Future<String?> _downloadImage(String url, Directory cacheDir) async {
    if (url.isEmpty) return null;
    try {
      final isSE = await DeviceInfoManager.isiPhoneSE();
      if (isSE) {
        url = url.cropParamsForSE;
      }
      final fileName = _generateFileName(url);
      final filePath = p.join(cacheDir.path, fileName);
      await _dio.download(url, filePath, deleteOnError: true);
      return filePath;
    } catch (e, s) {
      Log.e("下载 Splash 图片失败: $url", e, s);
      return null;
    }
  }

  Future<void> _cleanupObsoleteFiles(
    Directory directory,
    Set<String> keepPaths,
  ) async {
    if (!await directory.exists()) return;
    try {
      await for (final entity in directory.list()) {
        if (entity is File && !keepPaths.contains(entity.path)) {
          await entity.delete();
        }
      }
    } catch (e, s) {
      Log.e("清理 Splash 缓存文件失败", e, s);
    }
  }

  Future<Directory> _ensureCacheDirectory() async {
    final baseDir = await getApplicationDocumentsDirectory();
    final cacheDir = Directory(p.join(baseDir.path, _cacheDirName));
    if (!await cacheDir.exists()) {
      await cacheDir.create(recursive: true);
    }
    return cacheDir;
  }

  String _generateFileName(String url) {
    final uri = Uri.tryParse(url);
    final ext = uri == null ? null : p.extension(uri.path);
    final bytes = utf8.encode(url);
    final digest = md5.convert(bytes).toString();
    final safeExt = (ext?.isNotEmpty ?? false) ? ext : '.png';
    return '$digest$safeExt';
  }
}

final splashCacheServiceProvider = Provider<SplashCacheService>(
  (ref) => SplashCacheService(),
);
